package chat

import (
	"encoding/json"
	"fmt"
	"github.com/gorilla/websocket"
	"mall/common/globalkey"
	"strings"
	"sync"
	"time"
)

// https://github.com/zeromicro/zero-examples/blob/main/chat/internal/hub.go
type (
	Node struct {
		conn *websocket.Conn
		data chan []byte
	}
	ChatClient interface {
		WritePump(wg *sync.WaitGroup)
		ReadPump(wg *sync.WaitGroup)
	}
)

var (
	userProcessorCollector = sync.Map{}
)

const (
	// Time allowed to write a message to the peer.
	writeWait = 10 * time.Second

	// Time allowed to read the next pong message from the peer.
	pongWait = 60 * time.Second

	// Send pings to peer with this period. Must be less than pongWait.
	pingPeriod = (pongWait * 9) / 10

	// Maximum message size allowed from peer.
	maxMessageSize = 512

	// send buffer size
	bufSize = 256
)

func NewChatClient(conn *websocket.Conn, userId string) ChatClient {
	node := &Node{
		conn: conn,
		data: make(chan []byte),
	}
	userProcessorCollector.Store(userId, node)
	return node
}

type Message struct {
	MsgType  *uint32 `json:"msgType"`
	FriendId *string `json:"friendId"`
	Msg      *string `json:"msg"`
}

func (l *Node) WritePump(wg *sync.WaitGroup) {
	ticker := time.NewTicker(pingPeriod)
	defer func() {
		ticker.Stop()
		l.conn.Close()
		wg.Done()
	}()
	for {
		select {
		case data, ok := <-l.data:
			l.conn.SetWriteDeadline(time.Now().Add(writeWait))
			if !ok {
				l.conn.WriteMessage(websocket.CloseMessage, []byte{})
				return
			}
			l.conn.WriteMessage(websocket.TextMessage, data)
		case <-ticker.C:
			l.conn.SetWriteDeadline(time.Now().Add(writeWait))
			if err := l.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
				return
			}
		}
	}
}

func (l *Node) ReadPump(wg *sync.WaitGroup) {
	defer func() {
		err := l.conn.Close()
		if err != nil {
			return
		}
		wg.Done()
	}()
	for {
		_, message, err := l.conn.ReadMessage()
		if err != nil {
			fmt.Printf("read failed: %v", err)
			//node.webCon.Close()
			return
		}
		// 转发给接收者
		sendRevice(message)
	}
}

func sendRevice(msg []byte) {
	var message = &Message{}
	json.Unmarshal(msg, message)
	if message.Msg != nil && len(strings.TrimSpace(*message.Msg)) > 0 {
		//微信内容审核
		//err = l.svcCtx.MiniProgram.GetContentSecurity().CheckText(*req.PostContent)
		//if err != nil {
		//	return nil, resultx.NewErrCode(resultx.FORUM_POST_CONTENT_INVALID)
		//}
		if message.MsgType != nil {
			if *message.MsgType == globalkey.ChatMessageTypeSys {
				sendSysMessage(msg)
			}
			if *message.MsgType == globalkey.ChatMessageTypeGroup && message.FriendId != nil && len(strings.TrimSpace(*message.FriendId)) > 4 {
				sendGroupMessage(msg, *message.FriendId)
			}
			if *message.MsgType == globalkey.ChatMessageTypePrivate && message.FriendId != nil && len(strings.TrimSpace(*message.FriendId)) > 0 {
				sendPrivateMessage(msg, *message.FriendId)
			}
		}
	}
}

func sendSysMessage(msg []byte) {
	userProcessorCollector.Range(func(key, value interface{}) bool {
		node := value.(*Node)
		if node.data != nil {
			node.data <- msg
		}
		return true
	})
}
func sendGroupMessage(msg []byte, friendId string) {
	for _, id := range strings.Split(friendId, ",") {
		if v, ok := userProcessorCollector.Load(id); ok {
			node := v.(*Node)
			if node != nil {
				node.data <- msg
			}
		}
	}
}
func sendPrivateMessage(msg []byte, friendId string) {
	if v, ok := userProcessorCollector.Load(friendId); ok {
		node := v.(*Node)
		if node != nil {
			node.data <- msg
		}
	}
}
